import asyncio
from http import HTTPStatus
import dashscope
import requests
import csv
import uvicorn
from dashscope import Generation
from fastapi import FastAPI, File, UploadFile, Request, HTTPException
import os
import shutil
import time
import random
import string
from pydantic import BaseModel
from starlette.middleware.cors import CORSMiddleware

from fastapi.responses import StreamingResponse
import json
from io import BytesIO

rate_limit = 0
inappropriate = 1
dashscope.api_key = 'sk-f50759b51de2445b9a99c5f9a294c6b1' # AIStepfather

# dashscope.api_key = 'sk-01fc9ce61deb4d7b8469c07f4542fc11'
local_img_path_prefix = "file://D:/testPython/palmistry/"

multiModalPrompt = """请通过感情线分析该手相的感情运
"""

textPrompt1 = """"# 角色
你是一名
"""

textPrompt2 = """# 角色
你是一位
"""


class TotalInfo(BaseModel):
    file_name: str
    img_name: str
    img_desc: str
    sequence: str
    content: str
    age: str
    job: str
    time: str
    gender: str
    img_analyse: str
    personality_card: str


class TestInfo(BaseModel):
    multiModalPrompt: str
    textPrompt1: str
    textPrompt2: str
    file_name: str
    img_name: str
    sequence: str
    content: str
    age: str
    job: str
    time: str
    gender: str


class ConcludeInfo(BaseModel):
    content: str
    file_name: str


class PicInfo(BaseModel):
    file_name: str
    img_name: str
    sequence: str
    content: str
    age: str
    job: str
    time: str
    gender: str


class PicDescInfo(BaseModel):
    file_name: str
    img_name: str
    img_desc: str
    sequence: str
    content: str
    age: str
    job: str
    time: str
    gender: str


app = FastAPI()
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


# 获取multiModalPrompt和textPrompt1
@app.get("/prompts")
async def get_prompt():
    return {"multiModalPrompt": multiModalPrompt,
            "textPrompt1": textPrompt1,
            "textPrompt2": textPrompt2}


from fastapi.responses import StreamingResponse


@app.post("/analyse/img_desc/stream")
async def analyse_pic_desc_stream(pic_info: PicDescInfo):
    filename = pic_info.file_name

    # img_desc = '描述'
    img_desc = pic_info.img_desc

    # print("图片描述")
    # print(img_desc)

    # print("问题")
    question = build_question2(img_desc, pic_info)

    headers = {
        "Content-Type": "text/plain"
    }

    response = StreamingResponse(stream_call_text(textPrompt1, question), headers=headers, media_type="text/plain")
    return response


@app.post("/conclude/stream")
async def conclude_analyse_res_stream(conclude_info: ConcludeInfo):
    analyse_res = conclude_info.content

    headers = {
        "Content-Type": "text/plain"
    }

    response = StreamingResponse(stream_call_text(textPrompt2, analyse_res), headers=headers, media_type="text/plain")
    return response


@app.get("/stream")
async def stream_data():
    # 假设你有一个生成数据的异步生成器
    # 创建一个StreamingResponse对象
    headers = {
        "Content-Type": "text/plain"
    }

    response = StreamingResponse(stream_call_text("你是厨艺大师", "怎么做番茄炖牛腩"), headers=headers,
                                 media_type="text/plain")
    return response


async def stream_call_text(prompt: str, question: str):
    messages = [{'role': 'system', 'content': prompt},
                {'role': 'user', 'content': question}]
    responses = Generation.call(model="qwen-max",
                                messages=messages,
                                result_format='message',  # 设置输出为'message'格式
                                stream=True,  # 设置输出方式为流式输出
                                incremental_output=True  # 增量式流式输出
                                )
    for response in responses:
        if response.status_code == HTTPStatus.OK:
            cur_message = response.output.choices[0]['message']['content']
            # print(cur_message, end='')
            # data = {'result': f'{cur_message}'}
            # # 将数据转换为JSON格式的字符串
            # json_data = json.dumps(data)
            # # 将字符串转换为byte，并添加换行符，以便客户端逐行读取
            # stream_data = f"{json_data}"
            # print(cur_message,end='')
            # yield stream_data
            yield cur_message
            # # 停止2ms
            await asyncio.sleep(0.1)  # 模拟异步操作


# 保存全部信息
@app.post("/total")
async def save_total_info(pic_info: TotalInfo):
    with open('total_info24_5_6.csv', 'a', newline='', encoding='utf-8') as file:
        writer = csv.writer(file)
        writer.writerow([pic_info.file_name, pic_info.img_name, pic_info.img_desc, pic_info.sequence, pic_info.content,
                         pic_info.age, pic_info.job, pic_info.time, pic_info.gender, pic_info.img_analyse, pic_info.personality_card])

@app.post("/test")
async def test_prompt(pic_info: TestInfo):
    filename = pic_info.file_name

    print(pic_info)
    # img_desc = '描述'
    img_desc = simple_multimodal_conversation_call_with_prompt(filename, pic_info.multiModalPrompt)
    # print("图片描述")
    # print(img_desc)

    print("问题")
    question = build_question_for_test(img_desc, pic_info)
    print(question)

    print(question)
    # result1 = '结果'
    result1 = call_with_messages_prompt(question, pic_info.textPrompt1)
    print("第一步处理的结果")
    print(result1)
    if not is_empty(pic_info.textPrompt2):
        result1 = call_with_messages_prompt(result1, pic_info.textPrompt2)

    print(result1)

    # 将结果写入csv文件中(列为filename, img_desc, result1)
    with open('test_data.csv', 'a', newline='', encoding='utf-8') as file:
        writer = csv.writer(file)
        writer.writerow([filename, pic_info.img_name, pic_info.sequence, pic_info.content, pic_info.age, pic_info.job,
                         pic_info.time, pic_info.multiModalPrompt, pic_info.textPrompt1, pic_info.textPrompt2, img_desc,
                         result1])

    return {"filename": filename,
            # "img_desc": img_desc,
            "result": result1}


@app.post("/conclude")
async def conclude_analyse_res(conclude_info: ConcludeInfo):
    analyse_res = conclude_info.content
    overall_res = call_with_messages_prompt(analyse_res, textPrompt2)
    filename = conclude_info.file_name

    # 将结果写入csv文件中(列为filename, img_desc, result1)
    with open('conclude_res_24_5_6.csv', 'a', newline='', encoding='utf-8') as file:
        writer = csv.writer(file)
        writer.writerow([filename, overall_res])

    return {"result": overall_res}


@app.post("/analyse/img")
async def analyse_pic_self(pic_info: PicInfo):
    filename = pic_info.file_name

    print(pic_info)

    # img_desc = '描述'
    img_desc = simple_multimodal_conversation_call_with_prompt(filename, multiModalPrompt)

    # print("图片描述")
    # print(img_desc)

    # result1 = '结果'
    # 停止2s
    # time.sleep(2)

    # result2 = call_with_messages_prompt(result1, textPrompt2)

    # 将结果写入csv文件中(列为filename, img_desc, result1)
    # with open('img_desc24_5_6.csv', 'a', newline='', encoding='utf-8') as file:
    #     writer = csv.writer(file)
    #     writer.writerow([filename, pic_info.img_name, pic_info.sequence, pic_info.content, pic_info.age, pic_info.job,
    #                      pic_info.time, img_desc])
    final_result = img_desc

    return {"filename": filename,
            # "img_desc": img_desc,
            "result": final_result}


@app.post("/analyse/img_desc")
async def analyse_pic_desc(pic_info: PicDescInfo):
    filename = pic_info.file_name

    # img_desc = '描述'
    img_desc = pic_info.img_desc

    # print("图片描述")
    # print(img_desc)

    print("问题")
    question = build_question2(img_desc, pic_info)
    print(question)

    print(question)

    # result1 = '结果'
    # 停止2s
    # time.sleep(2)
    result1 = call_with_messages(question)

    # result2 = call_with_messages_prompt(result1, textPrompt2)

    # 将结果写入csv文件中(列为filename, img_desc, result1)
    with open('img_analyse24_5_6.csv', 'a', newline='', encoding='utf-8') as file:
        writer = csv.writer(file)
        writer.writerow([filename, pic_info.img_name, pic_info.sequence, pic_info.content, pic_info.age, pic_info.job,
                         pic_info.time, img_desc, result1])
    final_result = result1

    return {"filename": filename,
            # "img_desc": img_desc,
            "result": final_result}


@app.post("/analyse")
async def analyse_pic(pic_info: PicInfo):
    filename = pic_info.file_name

    print(pic_info)

    # img_desc = '描述'
    img_desc = simple_multimodal_conversation_call(filename)

    # print("图片描述")
    # print(img_desc)

    print("问题")
    question = build_question(img_desc, pic_info)
    print(question)

    print(question)

    # result1 = '结果'
    # 停止2s
    # time.sleep(2)
    result1 = call_with_messages(question)

    # result2 = call_with_messages_prompt(result1, textPrompt2)

    print("结果")
    # print(result1)

    # 将结果写入csv文件中(列为filename, img_desc, result1)
    with open('full_data24_5_6.csv', 'a', newline='', encoding='utf-8') as file:
        writer = csv.writer(file)
        writer.writerow([filename, pic_info.img_name, pic_info.sequence, pic_info.content, pic_info.age, pic_info.job,
                         pic_info.time, img_desc, result1])
    final_result = result1

    return {"filename": filename,
            # "img_desc": img_desc,
            "result": final_result}


@app.post("/only/upload/image")
async def only_upload_image(file: UploadFile = File(...)):
    # 生成随机文件名
    random_str = ''.join(random.sample(string.ascii_letters + string.digits, 8))
    filename = f"{random_str}_{file.filename}"
    # 保存文件
    with open(f"{filename}", "wb") as f:
        shutil.copyfileobj(file.file, f)

    return {"filename": filename}


@app.post("/upload/image")
async def upload_image(file: UploadFile = File(...)):
    # 生成随机文件名
    random_str = ''.join(random.sample(string.ascii_letters + string.digits, 8))
    filename = f"{random_str}_{file.filename}"
    # 保存文件
    with open(f"{filename}", "wb") as f:
        shutil.copyfileobj(file.file, f)
    # img_desc = 'dada'
    img_desc = simple_multimodal_conversation_call(filename)
    print("图片描述")
    print(img_desc)

    # result1 = '565'
    result1 = call_with_messages(img_desc)
    print("结果")
    print(result1)

    # 将结果写入csv文件中(列为filename, img_desc, result1)
    with open('data.csv', 'w', newline='') as file:
        writer = csv.writer(file)
        writer.writerow([filename, img_desc, result1])

    return {"filename": filename, "img_desc": img_desc, "result": result1}


def simple_multimodal_conversation_call(img_name: str):
    """Simple single round multimodal conversation call.
    """

    local_file_path1 = f'{local_img_path_prefix}{img_name}'
    # local_file_path1 = 'https://wx3.sinaimg.cn/large/c288eadaly1his4dvm5ojj20j60j6zm7.jpg'

    messages = [
        {
            "role": "user",
            "content": [
                {"image": local_file_path1},
                {"text": """你是一位

"""}
            ]
        }
    ]
    response = dashscope.MultiModalConversation.call(model='qwen-vl-max',
                                                     messages=messages)
    # The response status_code is HTTPStatus.OK indicate success,
    # otherwise indicate request is failed, you can get error code
    # and message from code and message.
    print(response)
    if response.status_code == HTTPStatus.OK:
        # print(response)
        content_text = response.output.choices[0].message.content[0]['text']
        role = response.output.choices[0].message.role
        # print(f"role: {role}, content_text: {content_text}")
        return content_text
    else:
        print(response.status_code)  # The error code.
        print(response.code)  # The error code.
        print(response.message)  # The error message.

        if response.status_code == 429:
            return rate_limit
        if response.status_code == 400:
            return inappropriate

        return None


def simple_multimodal_conversation_call_with_prompt(img_name: str, prompt: str):
    if is_empty(prompt):
        prompt = multiModalPrompt

    """Simple single round multimodal conversation call.
    """

    local_file_path1 = f'{local_img_path_prefix}{img_name}'
    # local_file_path1 = 'https://wx3.sinaimg.cn/large/c288eadaly1his4dvm5ojj20j60j6zm7.jpg'

    messages = [
        {
            "role": "user",
            "content": [
                {"image": local_file_path1},
                {"text": prompt}
            ]
        }
    ]
    response = dashscope.MultiModalConversation.call(model='qwen-vl-max',
                                                     messages=messages)
    # The response status_code is HTTPStatus.OK indicate success,
    # otherwise indicate request is failed, you can get error code
    # and message from code and message.
    print(response)
    if response.status_code == HTTPStatus.OK:
        # print(response)
        content_text = response.output.choices[0].message.content[0]['text']
        role = response.output.choices[0].message.role
        # print(f"role: {role}, content_text: {content_text}")
        return content_text
    else:
        print(response.status_code)  # The error code.
        print(response.code)  # The error code.
        print(response.message)  # The error message.

        if response.status_code == 429:
            return rate_limit
        if response.status_code == 400:
            return inappropriate

        return None


def call_with_messages(question: str):
    messages = [{'role': 'system', 'content': """"# 角色
你是一名
"""},
                {'role': 'user', 'content': question}]
    # - 请注意。
    response = dashscope.Generation.call(
        dashscope.Generation.Models.qwen_max,
        messages=messages,
        result_format='message',  # set the result to be "message" format.
    )
    if response.status_code == HTTPStatus.OK:
        content_text = response.output.choices[0].message.content
        print(response)
        print(content_text)
        return content_text
    else:
        print('Request id: %s, Status code: %s, error code: %s, error message: %s' % (
            response.request_id, response.status_code,
            response.code, response.message
        ))


def call_with_messages_prompt(question: str, prompt: str):
    if is_empty(prompt):
        return question

    messages = [{'role': 'system', 'content': prompt},
                {'role': 'user', 'content': question}]
    # - 请注意
    response = dashscope.Generation.call(
        dashscope.Generation.Models.qwen_max,
        messages=messages,
        result_format='message',  # set the result to be "message" format.
    )
    if response.status_code == HTTPStatus.OK:
        content_text = response.output.choices[0].message.content
        print(response)
        print(content_text)
        return content_text
    else:
        print('Request id: %s, Status code: %s, error code: %s, error message: %s' % (
            response.request_id, response.status_code,
            response.code, response.message
        ))


# 拼接图片描述和问题(新的流程)
def build_question2(img_desc: str, pic_info: PicDescInfo):
    # 拼接question
    question = ""
    if pic_info.img_name:
        question += f"作画者给图片起的名字是：{pic_info.img_name}\n"
    if pic_info.sequence:
        question += f"作画的顺序是：{pic_info.sequence}\n"
    if pic_info.content:
        question += f"作画者自己对内容的描述是：{pic_info.content}\n"
    if pic_info.age:
        question += f"作画者的年龄是：{pic_info.age}\n"
    if pic_info.gender:
        question += f"作画者的性别是：{pic_info.gender}\n"
    if pic_info.job:
        question += f"作画者的职业是：{pic_info.job}\n"
    if pic_info.time:
        question += f"作画花费的时间（分钟）是：{pic_info.time}\n"
    question += f"分析师对图片特征的描述是：{img_desc}"
    return question


# 拼接图片描述和问题
def build_question(img_desc: str, pic_info: PicInfo):
    # 拼接question
    question = ""
    if pic_info.img_name:
        question += f"作画者给图片起的名字是：{pic_info.img_name}\n"
    if pic_info.sequence:
        question += f"作画的顺序是：{pic_info.sequence}\n"
    if pic_info.content:
        question += f"作画者自己对内容的描述是：{pic_info.content}\n"
    if pic_info.age:
        question += f"作画者的年龄是：{pic_info.age}\n"
    if pic_info.gender:
        question += f"作画者的性别是：{pic_info.gender}\n"
    if pic_info.job:
        question += f"作画者的职业是：{pic_info.job}\n"
    if pic_info.time:
        question += f"作画花费的时间（分钟）是：{pic_info.time}\n"
    question += f"分析师对图片特征的描述是：{img_desc}"
    return question


# 拼接图片描述和问题(test调试界面使用)
def build_question_for_test(img_desc: str, pic_info: TestInfo):
    # 拼接question
    question = ""
    if pic_info.img_name:
        question += f"作画者给图片起的名字是：{pic_info.img_name}\n"
    if pic_info.sequence:
        question += f"作画的顺序是：{pic_info.sequence}\n"
    if pic_info.content:
        question += f"作画者自己对内容的描述是：{pic_info.content}\n"
    if pic_info.age:
        question += f"作画者的年龄是：{pic_info.age}\n"
    if pic_info.gender:
        question += f"作画者的性别是：{pic_info.gender}\n"
    if pic_info.job:
        question += f"作画者的职业是：{pic_info.job}\n"
    if pic_info.time:
        question += f"作画花费的时间（分钟）是：{pic_info.time}\n"
    question += f"分析师对图片特征的描述是：{img_desc}"
    return question


@app.get("/hello")
def hello():
    return {"message": "Hello World"}


# 判断字符串是否为None,或为空
def is_empty(s):
    return s is None or not s.strip()


if __name__ == "__main__":
    # call_with_stream()
    uvicorn.run(app, host="0.0.0.0", port=8032)
    # call_with_messages('1+1=?')
